package com.zhuhjay.app.web.controller.system;

import cn.hutool.core.io.FileUtil;
import com.zhuhjay.common.base.annotation.ApiLimiter;
import com.zhuhjay.common.base.config.SystemConfig;
import com.zhuhjay.common.base.controller.BaseController;
import com.zhuhjay.common.base.exception.BasicBusinessException;
import com.zhuhjay.common.base.model.vo.HttpResult;
import com.zhuhjay.common.core.util.SecurityContextHolder;
import com.zhuhjay.common.security.context.LoginUserContext;
import com.zhuhjay.common.web.annotation.Matching;
import com.zhuhjay.common.web.enums.MatchingMode;
import com.zhuhjay.common.web.model.vo.PageInfoVo;
import com.zhuhjay.common.web.util.FileUtils;
import com.zhuhjay.service.system.model.dto.UserPageParamDto;
import com.zhuhjay.service.system.model.dto.UserPasswordDto;
import com.zhuhjay.service.system.model.dto.UserUpdateDto;
import com.zhuhjay.service.system.model.entity.SystemUser;
import com.zhuhjay.service.system.model.vo.UserInfoVo;
import com.zhuhjay.service.system.service.SystemMenuService;
import com.zhuhjay.service.system.service.SystemOauthService;
import com.zhuhjay.service.system.service.SystemUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.hibernate.validator.constraints.Range;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.io.File;
import java.io.IOException;

import static com.zhuhjay.common.base.constant.ApplicationConstant.AVATAR_PATH;
import static com.zhuhjay.common.base.constant.ApplicationConstant.PATH_SEPARATOR;
import static com.zhuhjay.common.base.enums.HttpCode.UPDATE_SUCCESS;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author Zhuhjay
 * @since 2023-02-25
 */
@Api(tags = "用户管理")
@Validated
@RestController
@RequestMapping("/user")
public class SystemUserController extends BaseController {

    @Resource
    private SystemUserService userService;
    @Resource
    private SystemMenuService menuService;
    @Resource
    private SystemConfig systemConfig;
    @Resource
    private SystemOauthService oauthService;

    @ApiOperation("获取用户信息")
    @GetMapping
    public UserInfoVo userInfo() {
        SystemUser user = userService.getById(LoginUserContext.getUserId());
        UserInfoVo userInfo = UserInfoVo.of(user, false);
        userInfo.setPermissions(menuService.getPermissionsVoByUserId(user.getId()));
        userInfo.setBindWx(oauthService.isBindWx(user.getId()));
        return userInfo;
    }

    @ApiOperation("更新用户信息")
    @PutMapping
    public HttpResult<?> update(@RequestBody @Valid UserUpdateDto userUpdateDto) {
        // 获取登录用户的id
        int userId = SecurityContextHolder.getLoginUserDetail().getId();
        SystemUser user = userUpdateDto.bean2Entity();
        user.setId(userId);
        userService.updateById(user);
        return HttpResult.ok(UPDATE_SUCCESS);
    }

    @ApiOperation("更新用户头像")
    @PostMapping("avatar")
    public HttpResult<?> updateAvatar(@RequestPart MultipartFile file) {
        FileUtils.checkFileIsImage(file);
        final String dirPath = systemConfig.getAvatarPath();
        // 创建存放头像的文件夹，如果不存在
        File avatar = FileUtil.mkdir(dirPath);
        // 生成文件名
        String fileName = FileUtils.generateFileName(file.getOriginalFilename());
        try {
            FileUtil.writeBytes(file.getBytes(), avatar + File.separator + fileName);
        } catch (IOException e) {
            e.printStackTrace();
            return HttpResult.fail("头像上传失败");
        }
        // 获取当前登录用户，更新头像
        SystemUser user = new SystemUser();
        user.setId(SecurityContextHolder.getLoginUserDetail().getId());
        user.setAvatar("/profile/" + AVATAR_PATH + PATH_SEPARATOR + fileName);
        userService.updateById(user);
        return HttpResult.ok(UPDATE_SUCCESS);
    }

    @ApiOperation("更新用户密码")
    @PostMapping("password")
    public HttpResult<?> updatePassword(@RequestBody @Valid UserPasswordDto userPassword) {
        // 检查旧密码是否正确(过程有问题直接抛出异常)
        userService.checkPassword(userPassword.getOldPassword());
        // 如果两个密码一致，直接返回
        if (userPassword.getNewPassword().equals(userPassword.getOldPassword())) {
            return HttpResult.ok(UPDATE_SUCCESS);
        }
        // 修改密码
        userService.updatePassword(userPassword.getNewPassword());
        return HttpResult.ok(UPDATE_SUCCESS);
    }

    @ApiLimiter(limit = 2, expire = 10)
    @ApiOperation("请求绑定邮箱")
    @GetMapping("bind/email/{email}")
    public HttpResult<?> send2BindEmail(@PathVariable @Matching(MatchingMode.Email) String email) {
        userService.send2BindEmail(email);
        return HttpResult.ok("已发送绑定邮件，请注意查收");
    }

    @ApiLimiter(limit = 2, expire = 10)
    @ApiOperation("请求解绑邮箱")
    @GetMapping("unbind/email")
    public HttpResult<?> send2UnbindEmail() {
        userService.send2UnbindEmail();
        return HttpResult.ok("已发送解绑邮件，请注意查收");
    }

    // ---------------------- 管理员权限 ----------------------

    @ApiOperation("分页查询用户")
    @PreAuthorize("@perm.hasPerm('system:authority:user:list')")
    @GetMapping("page/{pageNum}/{pageSize}")
    public PageInfoVo<UserInfoVo> page(
            @PathVariable @Range(min = 1, max = Integer.MAX_VALUE) Integer pageNum,
            @PathVariable @Range(min = 5, max = 30) Integer pageSize,
            UserPageParamDto param) {
        if (param != null && param.getStatus() != null) {
            if (param.getStatus() < 0 || param.getStatus() > 1) {
                throw new BasicBusinessException("状态码错误");
            }
        }
        return userService.usersPage(pageNum, pageSize, param);
    }

    @ApiOperation("禁用/启用用户")
    @PreAuthorize("@perm.hasPerm('system:authority:user:status')")
    @PutMapping("status/{userId}")
    public HttpResult<?> updateStatus(@PathVariable Integer userId) {
        // 禁止禁用超级管理员
        checkUpdateAdmin(userId);
        userService.updateStatus(userId);
        return HttpResult.ok(UPDATE_SUCCESS);
    }

    @ApiOperation("修改用户角色")
    @PreAuthorize("@perm.hasPerm('system:authority:user:role')")
    @PutMapping("role/{userId}/{roleId}")
    public HttpResult<?> updateRole(
            @PathVariable @Min(value = 1, message = "请求失败") Integer userId,
            @PathVariable @Min(value = 1, message = "请求失败") Integer roleId) {
        // 禁止修改超级管理员
        checkUpdateAdmin(userId);
        // 禁止将超级管理员的角色分配给其他用户
        checkUpdateAdminRole(roleId);
        userService.updateRole(userId, roleId);
        return HttpResult.ok(UPDATE_SUCCESS);
    }

    @ApiOperation("重置用户密码")
    @PreAuthorize("@perm.hasPerm('system:authority:user:password')")
    @PutMapping("password/{userId}")
    public HttpResult<?> resetPassword(
            @PathVariable @Min(value = 1, message = "参数错误") Integer userId,
            @RequestBody @Matching(MatchingMode.Password) String password) {
        // 禁止修改超级管理员
        checkUpdateAdmin(userId);
        userService.resetPasswordByAdmin(userId, password);
        return HttpResult.ok(UPDATE_SUCCESS);
    }


}
